import tori.interface
import tori.settings
import random
from tori.binary import i_a_biren_osagarria, a_biren_osagarria
import gettext
_=gettext.gettext

class Bird():
    """Clase hau bird makina simulatzekoa balioko duen objektua sortzeko erabiliko
da. Elementu nagusiak erregistro multzoa EM, eta memoria RAM izango dira. 
    """
    def __init__(self):
        self.rodata = 0
        self.data   = 0
        self.bss    = 0
        self.text   = 0
        self.EM = [0]+[random.randint(0,2**16-1) for i in range(31)]
        self.PC = random.randint(0,2**16-1)
        self.IR = hex(random.randint(0,2**32-1))[2:].rstrip('L').upper().zfill(8)
        self.aldagaiak = []
        self.aginduak  = []
        self.dhasiera = 100
        self.ahasiera = 1600
        self.denborak = (70,70,5,10,20,30,50,10,20,15)
        self.instruction_set = [self.ld,self.ldd,self.ldx,self.st,self.std,self.stx,self.mova,self.mov,self.movi,self.add,
self.addi,self.sub,self.subi,self.mul,self.muli,self.div,self.divi,self.shr,self.shl,self.aand,
self.andi,self.oor,self.ori,self.xor,self.xori,self.jmp,self.beq,self.bne,self.bls,self.ble,self.bgt,
self.bge,self.retm,self.call,self.ret,self.push,self.pop,self.iin,self.out,self.outs,self.outm,self.outrm]
        self.instruction_names = ["LD","LDD","LDX","ST","STD","STX","MOVA","MOV","MOVI","ADD","ADDI",
"SUB","SUBI","MUL","MULI","DIV","DIVI","SHR","SHL","AND","ANDI","OR","ORI","XOR","XORI","JMP","BEQ","BNE","BLS",
"BLE","BGT","BGE","RETM","CALL","RET","PUSH","POP","IN","OUT","OUTS","OUTM","OUTRM"]
        self.memoria_aztarna = []
        self.maiz_din = [0 for i in range(len(self.instruction_set))]
        
        

    def er_f(self,r):
        return "R"+str(r).zfill(2)+"["+str(self.EM[r]).zfill(6)+"]"

    def ag_b(self, ag):
        return "PC="+str(self.PC).zfill(5)+" "+ag
    
    def gehi_k(self,*k):
        return " "+",".join(k)

    def bi_letra(self,x):
        a=hex(x)[2:].rstrip('L').zfill(4)
        return int(a[:2],16), int(a[2:],16)

#======AGINDUAK
    def ld(self,ir1,ir2):
        izena="LD"
        RH = int(ir1[6:11],2)
        M  = int(ir2,2)
        self.memoria_aztarna.append("D %s %d" % (_("Ir"),M+self.dhasiera))
        self.EM[RH] = self.aldagaiak[M]
        agindua=self.ag_b(izena)+self.gehi_k("r"+str(RH),"@"+str(M+self.dhasiera))
        rh=self.er_f(RH)
        mem="@"+str(M+self.dhasiera)
        edukia=self.aldagaiak[M]
        return ((agindua,None,None,rh,mem,edukia),None)

    def ldd(self,ir1,ir2):
        izena="LDD"        
        RH = int(ir1[6:11],2)
        RI = int(ir1[11:],2)
        ri=self.er_f(RI)
        M = self.EM[RI]+i_a_biren_osagarria(ir2)-self.dhasiera
        self.memoria_aztarna.append("D %s %d" % (_("Ir"),M+self.dhasiera))
        self.EM[RH] = self.aldagaiak[M]
        agindua=self.ag_b(izena)
        rh=self.er_f(RH)
        mem="@"+str(M+self.dhasiera)
        edukia=self.aldagaiak[M]
        return ((agindua,ri,None,rh,mem,edukia),None)

    def ldx(self,ir1,ir2):
        izena="LDX"
        RH = int(ir1[6:11],2)
        RI = int(ir1[11:],2)
        ri=self.er_f(RI)
        M = self.EM[RI]+int(ir2,2)
        self.memoria_aztarna.append("D %s %d" % (_("Ir"),M+self.dhasiera))
        self.EM[RH] = self.aldagaiak[M]
        agindua=self.ag_b(izena)
        rh=self.er_f(RH)
        mem="@"+str(M+self.dhasiera)
        edukia=self.aldagaiak[M]
        return ((agindua,ri,None,rh,mem,edukia),None)

    def st(self,ir1,ir2):
        izena="ST"
        RI = int(ir1[6:11],2)
        ri=self.er_f(RI)
        M = int(ir2,2)
        self.memoria_aztarna.append("D %s %d" % (_("Id"),M+self.dhasiera))
        self.aldagaiak[M]=self.EM[RI]
        agindua=self.ag_b(izena)+self.gehi_k("r"+str(RI),"@"+str(M+self.dhasiera))
        mem="@"+str(M+self.dhasiera)
        edukia=self.aldagaiak[M]
        return ((agindua,ri,None,None,mem,edukia),None)

    def std(self,ir1,ir2):
        izena="STD"
        RI1 = int(ir1[6:11],2)
        RI2 = int(ir1[11:],2)
        ri1=self.er_f(RI1)
        ri2=self.er_f(RI2)
        M = self.EM[RI2]+i_a_biren_osagarria(ir2)-self.dhasiera
        self.memoria_aztarna.append("D %s %d" % (_("Id"),M+self.dhasiera))
        self.aldagaiak[M] = self.EM[RI1]
        agindua=self.ag_b(izena)
        mem="@"+str(M+self.dhasiera)
        edukia=self.aldagaiak[M]
        return ((agindua,ri1,ri2,None,mem,edukia),None)

    def stx(self,ir1,ir2):
        izena="STX"
        RI1 = int(ir1[6:11],2)
        RI2 = int(ir1[11:],2)
        ri1=self.er_f(RI1)
        ri2=self.er_f(RI2)
        M = self.EM[RI2]+int(ir2,2)
        self.memoria_aztarna.append("D %s %d" % (_("Id"),M+self.dhasiera))
        self.aldagaiak[M] = self.EM[RI1]
        agindua=self.ag_b(izena)
        mem="@"+str(M+self.dhasiera)
        edukia=self.aldagaiak[M]
        return ((agindua,ri1,ri2,None,mem,edukia),None)

#================================

    def mova(self,ir1,ir2):
        izena="MOVA"
        RH = int(ir1[6:11],2)
        M  = int(ir2,2)
        self.EM[RH] = M +self.dhasiera
        agindua=self.ag_b(izena)+self.gehi_k("r"+str(RH),"@"+str(M+self.dhasiera))
        rh = self.er_f(RH)
        return ((agindua,rh,None,None,None,None),None)

    def mov(self,ir1,ir2):
        izena="MOV"
        RH = int(ir1[6:11],2)
        RI = int(ir1[11:],2)
        ri = self.er_f(RI)
        self.EM[RH] = self.EM[RI]
        agindua=self.ag_b(izena)+self.gehi_k("r"+str(RH),"r"+str(RI))
        rh = self.er_f(RH)
        return ((agindua,ri,None,rh,None,None),None)

    def movi(self,ir1,ir2):
        izena="MOVI"
        RH = int(ir1[6:11],2)
        K = i_a_biren_osagarria(ir2)
        self.EM[RH] = K
        agindua=self.ag_b(izena)+self.gehi_k("r"+str(RH),str(K))
        rh = self.er_f(RH)
        return ((agindua,None,None,rh,None,None),None)

#===================================

    def add(self,ir1,ir2):
        izena="ADD"
        RH  = int(ir1[6:11],2)
        RI1 = int(ir1[11:],2)
        RI2 = int(ir2[-5:],2)
        ri1=self.er_f(RI1)
        ri2=self.er_f(RI2)
        self.EM[RH] = self.EM[RI1]+self.EM[RI2]
        agindua=self.ag_b(izena)+self.gehi_k("r"+str(RH),"r"+str(RI1),"r"+str(RI2))
        rh=self.er_f(RH)
        return ((agindua,ri1,ri2,rh,None,None),None)

    def addi(self,ir1,ir2):
        izena="ADDI"
        RH  = int(ir1[6:11],2)
        RI = int(ir1[11:],2)
        ri = self.er_f(RI)
        K=i_a_biren_osagarria(ir2)
        self.EM[RH] = self.EM[RI]+K
        agindua=self.ag_b(izena)+self.gehi_k("r"+str(RH),"r"+str(RI),str(K))
        rh = self.er_f(RH) 
        return ((agindua,ri,None,rh,None,None),None)

    def sub(self,ir1,ir2):
        izena="SUB"
        RH  = int(ir1[6:11],2)
        RI1 = int(ir1[11:],2)
        RI2 = int(ir2[-5:],2)
        ri1=self.er_f(RI1)
        ri2=self.er_f(RI2)
        self.EM[RH] = self.EM[RI1]-self.EM[RI2]
        agindua=self.ag_b(izena)+self.gehi_k("r"+str(RH),"r"+str(RI1),"r"+str(RI2))
        rh=self.er_f(RH)
        return ((agindua,ri1,ri2,rh,None,None),None)

    def subi(self,ir1,ir2):
        izena="SUBI"
        RH  = int(ir1[6:11],2)
        RI = int(ir1[11:],2)
        ri = self.er_f(RI)
        K=i_a_biren_osagarria(ir2)
        self.EM[RH] = self.EM[RI]-K
        agindua=self.ag_b(izena)+self.gehi_k("r"+str(RH),"r"+str(RI),str(K))
        rh = self.er_f(RH) 
        return ((agindua,ri,None,rh,None,None),None)

    def mul(self,ir1,ir2):
        izena="MUL"
        RH  = int(ir1[6:11],2)
        RI1 = int(ir1[11:],2)
        RI2 = int(ir2[-5:],2)
        ri1=self.er_f(RI1)
        ri2=self.er_f(RI2)
        self.EM[RH] = self.EM[RI1]*self.EM[RI2]
        agindua=self.ag_b(izena)+self.gehi_k("r"+str(RH),"r"+str(RI1),"r"+str(RI2))
        rh=self.er_f(RH)
        return ((agindua,ri1,ri2,rh,None,None),None)

    def muli(self,ir1,ir2):
        izena="MULI"
        RH  = int(ir1[6:11],2)
        RI = int(ir1[11:],2)
        ri = self.er_f(RI)
        K=i_a_biren_osagarria(ir2)
        self.EM[RH] = self.EM[RI]*K
        agindua=self.ag_b(izena)+self.gehi_k("r"+str(RH),"r"+str(RI),str(K))
        rh = self.er_f(RH) 
        return ((agindua,ri,None,rh,None,None),None)

    def div(self,ir1,ir2):
        izena="DIV"
        RH  = int(ir1[6:11],2)
        RI1 = int(ir1[11:],2)
        RI2 = int(ir2[-5:],2)
        ri1=self.er_f(RI1)
        ri2=self.er_f(RI2)
        self.EM[RH] = self.EM[RI1]/self.EM[RI2]
        agindua=self.ag_b(izena)+self.gehi_k("r"+str(RH),"r"+str(RI1),"r"+str(RI2))
        rh=self.er_f(RH)
        return ((agindua,ri1,ri2,rh,None,None),None)

    def divi(self,ir1,ir2):
        izena="DIVI"
        RH  = int(ir1[6:11],2)
        RI = int(ir1[11:],2)
        ri = self.er_f(RI)
        K=i_a_biren_osagarria(ir2)
        self.EM[RH] = self.EM[RI]/K
        agindua=self.ag_b(izena)+self.gehi_k("r"+str(RH),"r"+str(RI),str(K))
        rh = self.er_f(RH) 
        return ((agindua,ri,None,rh,None,None),None)

#============================================

    def shr(self,ir1,ir2):
        izena="SHR"
        RH  = int(ir1[6:11],2)
        RI1 = int(ir1[11:],2)
        ri1=self.er_f(RI1)
        beh = int(ir2,2)
        self.EM[RH] = self.EM[RI1]/2**beh
        agindua=self.ag_b(izena)+self.gehi_k("r"+str(RH),"r"+str(RI1),"r"+str(beh))
        rh=self.er_f(RH)
        return ((agindua,ri1,None,rh,None,None),None)

    def shl(self,ir1,ir2):
        izena="SHL"
        RH  = int(ir1[6:11],2)
        RI1 = int(ir1[11:],2)
        ri1=self.er_f(RI1)
        beh = int(ir2,2)
        self.EM[RH] = self.EM[RI1]*2**beh
        agindua=self.ag_b(izena)+self.gehi_k("r"+str(RH),"r"+str(RI1),"r"+str(beh))
        rh=self.er_f(RH)
        return ((agindua,ri1,None,rh,None,None),None)

#==================================

    def aand(self,ir1,ir2):
        izena="AND"
        RH  = int(ir1[6:11],2)
        RI1 = int(ir1[11:],2)
        RI2 = int(ir2[-5:],2)
        ri1=self.er_f(RI1)
        ri2=self.er_f(RI2)
        a = a_biren_osagarria(self.EM[RI1])
        b = a_biren_osagarria(self.EM[RI2])
        c = ""
        for i in range(16):
            if a[i]!= '0' and b[i]!='0':
                c+='1'
            else:
                c+='0'
        self.EM[RH] = i_a_biren_osagarria(c)
        agindua=self.ag_b(izena)+self.gehi_k("r"+str(RH),"r"+str(RI1),"r"+str(RI2))
        rh=self.er_f(RH)
        return ((agindua,ri1,ri2,rh,None,None),None)
        

    def andi(self,ir1,ir2):
        izena="ANDI"
        RH  = int(ir1[6:11],2)
        RI1 = int(ir1[11:],2)
        ri1=self.er_f(RI1)
        beh = ir2
        a = a_biren_osagarria(self.EM[RI1])
        b = beh
        c = ""
        for i in range(16):
            if a[i]!= '0' and b[i]!='0':
                c+='1'
            else:
                c+='0'
        self.EM[RH] = i_a_biren_osagarria(c)
        K='b'+b
        agindua=self.ag_b(izena)+self.gehi_k("r"+str(RH),"r"+str(RI1),K)
        rh=self.er_f(RH)
        return ((agindua,ri1,None,rh,None,None),None)

    def oor(self,ir1,ir2):
        izena="OR"
        RH  = int(ir1[6:11],2)
        RI1 = int(ir1[11:],2)
        RI2 = int(ir2[-5:],2)
        ri1=self.er_f(RI1)
        ri2=self.er_f(RI2)
        a = a_biren_osagarria(self.EM[RI1])
        b = a_biren_osagarria(self.EM[RI2])
        c = ""
        for i in range(16):
            if a[i]!= '0' or b[i]!='0':
                c+='1'
            else:
                c+='0'
        self.EM[RH] = i_a_biren_osagarria(c)
        agindua=self.ag_b(izena)+self.gehi_k("r"+str(RH),"r"+str(RI1),"r"+str(RI2))
        rh=self.er_f(RH)
        return ((agindua,ri1,ri2,rh,None,None),None)

    def ori(self,ir1,ir2):
        izena="ORI"
        RH  = int(ir1[6:11],2)
        RI1 = int(ir1[11:],2)
        ri1=self.er_f(RI1)
        beh = ir2
        a = a_biren_osagarria(self.EM[RI1])
        b = beh
        c = ""
        for i in range(16):
            if a[i]!= '0' or b[i]!='0':
                c+='1'
            else:
                c+='0'
        self.EM[RH] = i_a_biren_osagarria(c)
        K='b'+b
        agindua=self.ag_b(izena)+self.gehi_k("r"+str(RH),"r"+str(RI1),K)
        rh=self.er_f(RH)
        return ((agindua,ri1,None,rh,None,None),None)

    def xor(self,ir1,ir2):
        izena="AND"
        RH  = int(ir1[6:11],2)
        RI1 = int(ir1[11:],2)
        RI2 = int(ir2[-5:],2)
        ri1=self.er_f(RI1)
        ri2=self.er_f(RI2)
        a = a_biren_osagarria(self.EM[RI1])
        b = a_biren_osagarria(self.EM[RI2])
        c = ""
        for i in range(16):
            if a[i]!=b[i]:
                c+='1'
            else:
                c+='0'
        self.EM[RH] = i_a_biren_osagarria(c)
        agindua=self.ag_b(izena)+self.gehi_k("r"+str(RH),"r"+str(RI1),"r"+str(RI2))
        rh=self.er_f(RH)
        return ((agindua,ri1,ri2,rh,None,None),None)

    def xori(self,ir1,ir2):
        izena="XORI"
        RH  = int(ir1[6:11],2)
        RI1 = int(ir1[11:],2)
        ri1 = self.er_f(RI1)
        beh = ir2
        a = a_biren_osagarria(self.EM[RI1])
        b = beh
        c = ""
        for i in range(16):
            if a[i]!=b[i]:
                c+='1'
            else:
                c+='0'
        self.EM[RH] = i_a_biren_osagarria(c)
        K='b'+b
        agindua=self.ag_b(izena)+self.gehi_k("r"+str(RH),"r"+str(RI1),K)
        rh=self.er_f(RH)
        return ((agindua,ri1,None,rh,None,None),None)

#===============================================

    def jmp(self,ir1,ir2):
        izena="JMP"
        DESP = i_a_biren_osagarria(ir2)
        agindua=self.ag_b(izena)
        self.PC+=DESP-2
        return ((agindua,None,None,None,None,None),None)

    def beq(self,ir1,ir2):
        izena="BEQ"
        RI = int(ir1[6:11],2)
        ri1=self.er_f(RI)
        DESP = i_a_biren_osagarria(ir2)
        agindua=self.ag_b(izena)
        if self.EM[RI]==0:
            self.PC+=DESP-2
        return ((agindua,ri1,None,None,None,None),None)

    def bne(self,ir1,ir2):
        izena="BNE"
        RI = int(ir1[6:11],2)
        ri1=self.er_f(RI)
        DESP = i_a_biren_osagarria(ir2)
        agindua=self.ag_b(izena)
        if self.EM[RI]!=0:
            self.PC+=DESP-2
        return ((agindua,ri1,None,None,None,None),None)

    def bls(self,ir1,ir2):
        izena="BLS"
        RI = int(ir1[6:11],2)
        ri1=self.er_f(RI)
        DESP = i_a_biren_osagarria(ir2)
        agindua=self.ag_b(izena)
        if self.EM[RI]<0:
            self.PC+=DESP-2
        return ((agindua,ri1,None,None,None,None),None)

    def ble(self,ir1,ir2):
        izena="BLE"
        RI = int(ir1[6:11],2)
        ri1=self.er_f(RI)
        DESP = i_a_biren_osagarria(ir2)
        agindua=self.ag_b(izena)
        if self.EM[RI]<=0:
            self.PC+=DESP-2
        return ((agindua,ri1,None,None,None,None),None)

    def bgt(self,ir1,ir2):
        izena="BGT"
        RI = int(ir1[6:11],2)
        ri1=self.er_f(RI)
        DESP = i_a_biren_osagarria(ir2)
        agindua=self.ag_b(izena)
        if self.EM[RI]>0:
            self.PC+=DESP-2
        return ((agindua,ri1,None,None,None,None),None)

    def bge(self,ir1,ir2):
        izena="BGE"
        RI = int(ir1[6:11],2)
        ri1=self.er_f(RI)
        DESP = i_a_biren_osagarria(ir2)
        agindua=self.ag_b(izena)
        if self.EM[RI]>=0:
            self.PC+=DESP-2
        return ((agindua,ri1,None,None,None,None),None)

#===================================================

    def retm(self,ir1,ir2):
        izena="RETM"
        agindua=self.ag_b(izena)
        return ((agindua,None,None,None,None,None),-1)

#===================================================

    def call(self,ir1,ir2):
        izena="CALL"
        DESP = i_a_biren_osagarria(ir2)
        self.EM[31]+=1
        M = self.EM[31]-self.dhasiera
        self.memoria_aztarna.append("D %s %d" % (_("Id"),M+self.dhasiera))
        mem="@"+str(M+self.dhasiera)
        edukia=self.aldagaiak[M]
        self.aldagaiak[M]=self.PC+2
        self.PC+=DESP-2
        agindua=self.ag_b(izena)+self.gehi_k("@"+str(self.PC+DESP))
        return ((agindua,None,None,None,mem,edukia),None)

    def ret(self,ir1,ir2):
        izena="RET"
        agindua=self.ag_b(izena)
        M = self.EM[31]-self.dhasiera
        self.memoria_aztarna.append("D %s %d" % (_("Ir"),M+self.dhasiera))
        mem="@"+str(M+self.dhasiera)
        edukia=self.aldagaiak[M]
        self.PC=self.aldagaiak[M]-2
        self.EM[31]-=1
        return ((agindua,None,None,None,mem,edukia),None)

    def push(self,ir1,ir2):
        izena="PUSH"
        RI = int(ir1[6:11],2)
        ri1=self.er_f(RI)
        self.EM[31]+=1
        M = self.EM[31]-self.dhasiera
        self.memoria_aztarna.append("D %s %d" % (_("Id"),M+self.dhasiera))
        mem="@"+str(M+self.dhasiera)
        edukia=self.aldagaiak[M]
        self.aldagaiak[M]=self.EM[RI]  
        agindua=self.ag_b(izena)+self.gehi_k("r"+str(RI))      
        return ((agindua,ri1,None,None,mem,edukia),None)

    def pop(self,ir1,ir2):
        izena="POP"
        RH = int(ir1[6:11],2)
        rh=self.er_f(RH)
        M = self.EM[31]-self.dhasiera
        self.memoria_aztarna.append("D %s %d" % (_("Id"),M+self.dhasiera))
        mem="@"+str(M+self.dhasiera)
        edukia=self.aldagaiak[M]
        self.EM[RH]=self.aldagaiak[M]
        self.EM[31]-=1
        agindua=self.ag_b(izena)+self.gehi_k("r"+str(RH))
        return ((agindua,None,None,rh,mem,edukia),None)

#===================================================

    def iin(self,ir1,ir2):
        izena="IN"
        self.EM[1] = tori.interface.sarreradialogoa(_("Sartu Zenbakia"))
        agindua=self.ag_b(izena)
        return ((agindua,None,None,self.er_f(1),None,None),"IN R1="+str(self.EM[1])+'\n')

    def out(self,ir1,ir2):
        izena="OUT"
        agindua=self.ag_b(izena)
        return ((agindua,self.er_f(1),None,None,None,None),"OUT R1="+str(self.EM[1])+'\n')

    def outs(self,ir1,ir2):
        izena="OUTS"
        i = int(ir2,2)
        katea= ""
        a,b=self.bi_letra(self.aldagaiak[i])
        while b!=0 and i<len(self.aldagaiak):
            katea+=chr(a)+chr(b)
            i+=1
            a,b=self.bi_letra(self.aldagaiak[i])
        katea+=a and chr(a) or ""
        agindua=self.ag_b(izena)+" "+katea
        return ((agindua,None,None,None,None,None),'OUTS "'+katea+'"\n')

    def outm(self,ir1,ir2):
        izena="OUTM"
        berehalakoa = int(ir1[-10:],2)
        helbidea = int(ir2,2)
        katea='\n    '.join(['@'+str(i+self.dhasiera+helbidea)+'='+str(self.aldagaiak[helbidea+i]) for i in range(berehalakoa)])
        agindua=self.ag_b(izena)
        return ((agindua,None,None,None,None,None),'OUTM \n    '+katea+'\n')

    def outrm(self,ir1,ir2):
        pass




